import * as d3 from 'd3'

function generateDataset(data, forward = 12) {
  const months = [], days = []

  for (let i = forward; i > 0; i--) {
    let referDate = new Date()

    referDate.setMonth(referDate.getMonth() - i + 2)

    if (i !== 1) referDate.setDate(0)
    else referDate.setMonth(referDate.getMonth() - 1)

    let month = referDate.getMonth() + 1
    months.push(month)
    month = month < 10 ? '0' + month : month

    for (let d = 1; d <= referDate.getDate(); d++) {
      let day = d < 10 ? '0' + d : d
      const date = referDate.getFullYear() + '-' + month + '-' + day
      const total = data.find(v => v.created_at === date)?.counting || 0
      days.push({ date, total })
    }

  }

  let firstDate = days[0].date
  let d = new Date(firstDate)
  let day = d.getDay() == 0 ? 7 : d.getDay()

  for (let i = 1; i < day; i++) {
    d.setDate(d.getDate() - i)
    let v = [d.getFullYear(), d.getMonth() + 1, d.getDate()]
    if (v[1] < 10) v[1] = '0' + v[1]
    if (v[2] < 10) v[2] = '0' + v[2]
    const date = v.join('-')
    const total = data.find(v => v.created_at === date)?.counting || 0
    days.unshift({ date, total })
  }

  return { days, months }
}


export default {

  init() {

    let width, height, margin = 30
    let weekBoxWidth = 20, monthBoxHeight = 20
    let dataset = []
    let max, selector, colorRange, tooltipEnabled
    let onClick = null
    let cellMargin, cellRadius
    let locales = {
      'en': {
        months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
        days: ['Sun', 'Tue', 'Thu', 'Sat'],
      },
      'zh-CN': {
        months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
        days: ['一', '三', '五', '日'],
      }

    }
    let locale = locales.en

    chart.width = function (value) { return arguments.length ? (width = value, chart) : width }
    chart.height = function (value) { return arguments.length ? (height = value, chart) : height }
    chart.margin = function (value) { return arguments.length ? (margin = value, chart) : margin }
    chart.cellMargin = function (value) { return arguments.length ? (cellMargin = value, chart) : cellMargin }
    chart.cellRadius = function (value) { return arguments.length ? (cellRadius = value, chart) : cellRadius }
    chart.max = function (value) { return arguments.length ? (max = value, chart) : max }
    chart.colorRange = function (value) { return arguments.length ? (colorRange = value, chart) : colorRange }
    chart.dataset = function (value) { return arguments.length ? (dataset = generateDataset(value), chart) : dataset }
    chart.tooltipEnabled = function (value) { return arguments.length ? (tooltipEnabled = value, chart) : tooltipEnabled }
    chart.selector = function (value) { return arguments.length ? (selector = value, chart) : selector }
    chart.onClick = function (value) { return arguments.length ? (onClick = value, chart) : onClick }
    chart.locale = function (value) {
      if (arguments.length) {
        if (value === 'en' || value === 'zh-CN') locale = locales[value]
        else locale = value
        return chart
      }
      return locale
    }

    function chart() {
      const svg = d3.select(selector)
        .style('position', 'relative')
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .attr('class', 'calendar-heatmap')

      if (max === null) max = d3.max(dataset.days, v => v.total)
      max = max === 0 ? 5 : max

      let color = d3.scaleLinear()
        .range(colorRange)
        .domain([0, max])

      drawMonth()
      drawWeek()
      drawDay()

      function drawMonth() {
        const monthBox = svg.append('g')
          .attr(
            'transform',
            'translate(' + (margin + weekBoxWidth) + ', ' + margin + ')'
          )
        const monthScale = d3.scaleLinear()
          .domain([0, dataset.months.length])
          .range([0, width - margin - weekBoxWidth])

        monthBox.selectAll('text').data(dataset.months).enter()
          .append('text')
          .text(v => { return locale.months[v - 1] })
          .attr('class', 'heatmap-month-text')
          .attr('x', (v, i) => monthScale(i))
      }

      function drawWeek() {
        const weekBox = svg.append('g')
          .attr('class', 'heatmap-week-box')
          .attr(
            'transform',
            'translate(' + (margin - 10) + ', ' + (margin + monthBoxHeight) + ')'
          )
        const weekScale = d3.scaleLinear()
          .domain([0, locale.days.length])
          .range([0, height - margin - monthBoxHeight + 14])

        weekBox.selectAll('text').data(locale.days).enter()
          .append('text')
          .text(v => { return v })
          .attr('class', 'heatmap-week-text')
          .attr('y', (v, i) => weekScale(i))
      }

      function drawDay() {
        const cellBox = svg.append('g')
          .attr('class', 'heatmap-day-box')
          .attr(
            'transform',
            'translate(' + (margin + weekBoxWidth) + ', ' + (margin + 10) + ')'
          )

        const cellSize = (height - margin - monthBoxHeight - cellMargin * 6 - 10) / 7
        let cellCol = 0
        let cell = cellBox.selectAll('rect')
          .data(dataset.days).enter()
          .append('rect')
          .attr('class', 'heatmap-day-cell')
          .attr('width', cellSize)
          .attr('height', cellSize)
          .attr('rx', cellRadius)
          .attr('fill', v => color(v.total))
          .attr('x', (v, i) => {
            if (i % 7 == 0) cellCol++
            let x = (cellCol - 1) * cellSize
            return cellCol > 1 ? x + cellMargin * (cellCol - 1) : x
          })
          .attr('y', (v, i) => {
            let y = i % 7
            return y > 0 ? y * cellSize + cellMargin * y : y * cellSize
          })

        let tooltip = document.getElementById('heatmap-tooltip')
        registerEvent()

        function registerEvent() {
          cell.on('click', onclick)
          if (!tooltipEnabled) return
          cell.on('mouseover', function (d, d1) {
            tooltip.innerHTML = tooltipHTMLForDate(d1)
            const rect = this.getBoundingClientRect()
            tooltip.style.visibility = 'visible'
            tooltip.style.opacity = 1
            tooltip.style.left = rect.x - 60 - cellSize / 2 + 'px'
            tooltip.style.top = d.pageY - cellSize - 55 + 'px'
          })
          cell.on('mouseout', function () {
            tooltip.style.visibility = 'hidden'
            tooltip.style.opacity = 0
          })
        }
      }
    }

    return chart

    function tooltipHTMLForDate(d) {
      return `
        <div class="heatmap-tooltip-date">${d.date}</div>
        <div class="heatmap-tooltip-total">${d.total}</div>
      `
    }
  }

}